import React, { memo } from 'react';
import { Route, Redirect, RouteProps } from 'react-router-dom';

export interface IRouterResult {
    pathname: string; // 跳转的路径
    state?: IRouterState;
}
export interface IAuthRouteProps extends RouteProps {
    onEnter?: (props: any) => IRouterResult | boolean;
    component: React.ComponentType | React.ExoticComponent;
    redirectTo?: IRouterResult;
    [key: string]: any; // 扩展，可以传入任意参数
}

export interface IRouterState {
    from: string; // 路径来源，方便从登陆页到达指定页面
}

export interface IRoute extends IAuthRouteProps {
    path: string;
    childrens?: IRoute[];
}

// 增加前置函数，用于控制权限等特殊处理,（权限信息保存sessionStoreage中去，去解决异步问题）
export const AuthRoute: React.FC<IAuthRouteProps> = memo((props) => {
    const { onEnter, component: Component, redirectTo, ...reset } = props;
    // 获取返回值
    const result = onEnter && onEnter(props);
    
    // result遵循这样的数据结构才可以 {pathname: '/login',state: {from: props.location.pathname}};
    if (typeof result === 'object') { // 自定义跳转方式，此处遵循路有对象规则，主要解决index.js:2178 Warning: Cannot update during an existing state transition (such as within `render`). 警告
        return <Redirect to={result}></Redirect>;
    } else {
        return (
            <Route render={(routeProps) => {
                // 将参数传递给onEnter方法中，以便于使用组件中的方法，如跳转/获取store数据
                // 最后的null更换成Redirect更合适,适应业务需求  (<Redirect to={{ pathname: '/login', state: { from: props.location.pathname } }}></Redirect>)
                return onEnter !== void 0 && result ? (<Component {...props}></Component>) : onEnter === void 0 ? (<Component {...props}></Component>) : <Redirect to={{ pathname: redirectTo?.pathname || '/authority' }}></Redirect>;
            }} {...reset}></Route>
        );
    }
});



export function createRoutes(routes: Array<IRoute> = [], results: Array<JSX.Element> = [], basePath = ''): Array<JSX.Element> {
    // 遍历所有节点，生成对应的DOM
    routes.forEach(({path, component, childrens, ...args}) => {
        // 如果未加"/"前缀进行自动补全，追加父节点的path
        let newPath =  path.startsWith('/') ? path : '/' + path;
        if (!newPath.startsWith(basePath)) {// 如果路径前缀和上级父节点一致，则认为用户配置为全路径
            newPath = basePath + newPath;
        }

        // 将对象转换为Route组件
        if(component) { // 没有组件不用去渲染Route，否则会抛异常
            results.push(<AuthRoute path={newPath} key={newPath} component={component} {...args}></AuthRoute>);
        }

        // 将原数组进行拆分（拍平）
        if (childrens && Array.isArray(childrens)) {
            createRoutes(childrens, results, newPath);
        }
    });

    // 将最终结果进行返回
    return results
}